package com.example.book.recommend;


import com.example.book.entity.Book;
import com.example.book.entity.User;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author jeff
 * @date 2023/04/07 18:58
 *
 **/
public class Algorithm {
    /*
    * 在给定username情况下 计算其他用户和它的距离并排序
    * @param username
    * @return
    */
    private Map<Double, String> computeNearestNeighbor(String username, List<User> users) {
        Map<Double,String> distances = new TreeMap<>();
        User u = new User(username);
        for(User user:users){
            if(username.equals(user.username)) {
                u = user;
            }
        }

        for(int i =0;i<users.size();i++) {
            User uu = users.get(i);

            if(!uu.username.equals(username)){
                double distance = pearson_dis(uu.bookList,u.bookList);
                distances.put(distance,uu.username);
            }
        }
        System.out.println("该用户与其他用户的皮尔森相关系数：" + distances);
        return distances;
    }

    /**
     * 计算2个评分序列的皮尔森距离
     * 选择公式进行计算
     * @param rat1,rat2
     * @return
     */
    private double pearson_dis(List<Book> rat1, List<Book> rat2) {
        int n = rat1.size();
        List<Integer> rat1scorecollect = rat1.stream().map(A -> A.score).collect(Collectors.toList());
        List<Integer> rat2scorecollect = rat2.stream().map(A -> A.score).collect(Collectors.toList());

        double ex = rat1scorecollect.stream().mapToDouble(x->x).sum();
        double ey = rat2scorecollect.stream().mapToDouble(y->y).sum();
        double ex2 = rat1scorecollect.stream().mapToDouble(x->Math.pow(x,2)).sum();
        double ey2 = rat2scorecollect.stream().mapToDouble(y->Math.pow(y,2)).sum();

        double exy = IntStream.range(0,n).mapToDouble(i->rat1scorecollect.get(i)*rat2scorecollect.get(i)).sum();
        double numerator = exy * ex * ey /n;
        double denoominator = Math.sqrt((ex2 - Math.pow(ex,2)/n) * (ey2 - Math.pow(ey,2)/n));

        if(denoominator == 0) return 0.0;
        return numerator / denoominator;
    }

    public List<Book> Algorithm(String username , List<User> users) {
        //根据最近邻找到
        Map<Double,String> distances = computeNearestNeighbor(username,users);
        String nearest = distances.values().iterator().next();


        //找到最近邻浏览 进行推荐
        User neighborrat = new User();
        for(User user:users) {
            if(nearest.equals(user.username)) {
                neighborrat = user;
            }
        }
        System.out.println("最近邻浏览图书：" + neighborrat.bookList);

        User userrats = new User();
        for(User user:users) {
            if(username.equals(user.username)){
                userrats = user;
            }
        }
        System.out.println("用户浏览的图书：" + userrats.bookList);

        //根据自己和近邻的计算评分推荐图书
        List<Book> recommendationBook = new ArrayList<>();
        for(Book book : neighborrat.bookList) {
            if(userrats.find(book.name) == null) {
                //确保自己没有浏览过
                recommendationBook.add(book);
            }
        }
        Collections.sort(recommendationBook);//根据评分排列推荐
        return recommendationBook;
    }
}
